package com.xinyu.notification;

import com.xinyu.config.NotificationProperties;
import com.xinyu.domain.User;
import com.xinyu.event.StatusChangeEvent;
import com.xinyu.service.IUserService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.mail.internet.MimeMessage;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component
public class StatusChangeEventListener {

    private static final Logger log = LoggerFactory.getLogger(StatusChangeEventListener.class);
    private static final String TEMPLATE_NAME = "status-change-email.html";
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    private final JavaMailSender mailSender;
    private final NotificationProperties notificationProperties;
    private final MailTemplateRenderer templateRenderer;
    private final IUserService userService;

    public StatusChangeEventListener(JavaMailSender mailSender,
                                     NotificationProperties notificationProperties,
                                     MailTemplateRenderer templateRenderer,
                                     IUserService userService) {
        this.mailSender = mailSender;
        this.notificationProperties = notificationProperties;
        this.templateRenderer = templateRenderer;
        this.userService = userService;
    }

    @Async("notificationExecutor")
    @EventListener
    public void handleStatusChange(StatusChangeEvent event) {
        if (!notificationProperties.isEnabled()) {
            return;
        }
        if (event == null || !event.isMeaningfulChange()) {
            return;
        }
        List<Integer> targetUserIds = event.getRecipientUserIds();
        if (targetUserIds == null || targetUserIds.isEmpty()) {
            return;
        }
        Set<Integer> distinctIds = targetUserIds.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        if (distinctIds.isEmpty()) {
            return;
        }
        List<User> recipients = userService.listByIds(distinctIds);
        if (recipients == null || recipients.isEmpty()) {
            return;
        }
        User operator = event.getOperatorId() == null ? null : userService.getById(event.getOperatorId());
        Map<Integer, User> recipientIndex = recipients.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(User::getId, Function.identity(), (left, right) -> left));
        String changeSummary = buildChangeSummary(event, recipientIndex);
        for (User user : recipients) {
            if (user == null) {
                continue;
            }
            if (Objects.equals(user.getId(), event.getOperatorId())) {
                continue;
            }
            if (user.getEmailNotifyEnabled() == null || user.getEmailNotifyEnabled() == 0) {
                continue;
            }
            if (StringUtils.isBlank(user.getEmail())) {
                continue;
            }
            sendMail(user, operator, event, changeSummary);
        }
    }

    private void sendMail(User target, User operator, StatusChangeEvent event, String changeSummary) {
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, StandardCharsets.UTF_8.name());
            helper.setTo(target.getEmail());
            helper.setFrom(notificationProperties.getFrom());
            helper.setSubject(buildSubject(event, changeSummary));
            helper.setText(buildBody(target, operator, event, changeSummary), true);
            mailSender.send(message);
        } catch (Exception ex) {
            log.warn("发送{}状态通知给{}失败: {}", event.getEntityType(), target.getEmail(), ex.getMessage());
        }
    }

    private String buildSubject(StatusChangeEvent event, String changeSummary) {
        String summary = StringUtils.defaultIfBlank(changeSummary, event.getNewStateLabel());
        return String.format("[%s]%s：%s", event.getEntityType().getDisplayName(),
                StringUtils.defaultIfBlank(event.getEntityTitle(), "#" + event.getEntityId()),
                StringUtils.defaultIfBlank(summary, "状态更新"));
    }

    private String buildBody(User target, User operator, StatusChangeEvent event, String changeSummary) {
        Map<String, Object> variables = new HashMap<>();
        variables.put("username", StringUtils.defaultIfBlank(target.getRealname(), target.getUsername()));
        variables.put("entityType", event.getEntityType().getDisplayName());
        variables.put("title", StringUtils.defaultIfBlank(event.getEntityTitle(), "#" + event.getEntityId()));
        variables.put("newState", event.getNewStateLabel());
        variables.put("reason", StringUtils.defaultIfBlank(event.getReason(), "无"));
        variables.put("detailUrl", StringUtils.defaultIfBlank(event.getDetailUrl(), ""));
        variables.put("operator", operator == null ? "系统" : StringUtils.defaultIfBlank(operator.getRealname(), operator.getUsername()));
        variables.put("timestamp", LocalDateTime.now().format(FORMATTER));
        variables.put("changeSummary", StringUtils.defaultIfBlank(changeSummary, "状态更新"));
        String rendered = templateRenderer.render(TEMPLATE_NAME, variables);
        if (rendered != null) {
            return rendered;
        }
        // fallback to plain text
        return variables.get("username") + "，您好：\n\n" +
                String.format("%s《%s》%s。当前状态：%s。原因：%s。详情：%s",
                        variables.get("entityType"), variables.get("title"), variables.get("changeSummary"),
                        variables.get("newState"),
                        variables.get("reason"), StringUtils.defaultIfBlank((String) variables.get("detailUrl"), "请登录系统查看"));
    }

    private String buildChangeSummary(StatusChangeEvent event, Map<Integer, User> recipientIndex) {
        StringBuilder summary = new StringBuilder();
        if (event.isStateChanged() && StringUtils.isNotBlank(event.getNewStateLabel())) {
            summary.append("状态更新为 ").append(event.getNewStateLabel());
        }
        if (event.isAssigneeChanged()) {
            String assigneeName = resolveUserName(event.getNewResponsibleUserId(), recipientIndex);
            if (summary.length() > 0) {
                summary.append("，");
            }
            summary.append("责任人调整");
            if (StringUtils.isNotBlank(assigneeName)) {
                summary.append("为 ").append(assigneeName);
            }
        }
        if (summary.length() == 0) {
            summary.append("状态更新");
        }
        return summary.toString();
    }

    private String resolveUserName(Integer userId, Map<Integer, User> recipientIndex) {
        if (userId == null) {
            return null;
        }
        User user = recipientIndex == null ? null : recipientIndex.get(userId);
        if (user == null) {
            user = userService.getById(userId);
        }
        if (user == null) {
            return null;
        }
        return StringUtils.defaultIfBlank(user.getRealname(), user.getUsername());
    }
}
